package br.com.ordersys.web.services;

import java.sql.Timestamp;
import java.util.Collection;
import java.util.UUID;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import br.com.ordersys.framework.db.DBSessionManager;
import br.com.ordersys.framework.db.IDBSession;
import br.com.ordersys.framework.db.IValueObject;
import br.com.ordersys.framework.db.Query;
import br.com.ordersys.framework.i18n.I18n;
import br.com.ordersys.framework.restlayer.RestCall;
import br.com.ordersys.framework.restlayer.RestCallContext;
import br.com.ordersys.framework.restlayer.auth.AuthenticationData;
import br.com.ordersys.framework.restlayer.auth.AuthenticationService;
import br.com.ordersys.web.data.FilaEmailVO;
import br.com.ordersys.web.data.UsuarioVO;
import br.com.ordersys.web.utils.UserPictureUtils;

@Service("user")
public class UserServices implements IUserServices {
	private I18n i18n = new I18n(this.getClass());
	
	@Transactional
	@RestCall(inputTypeClass = IUserServices.ChangePasswordInput.class)
	@Override
	public void changePassword() {
		IDBSession dbSession = null;
		try {
			dbSession = DBSessionManager.open();
			AuthenticationData auth = RestCallContext.get().getAuthenticationData();
			ChangePasswordInput input = (ChangePasswordInput) RestCallContext.get().getInputObject();
			UsuarioVO usuVO = dbSession.findByPK(UsuarioVO.class, auth.getUserID());

			usuVO.setPSW(input.getPassword());
			usuVO.save();
		} finally {
			DBSessionManager.close(dbSession);
		}
	}

	@Transactional
	@RestCall
	@Override
	public void removePicture() {
		IDBSession dbSession = null;
		try {
			dbSession = DBSessionManager.open();
			AuthenticationData auth = RestCallContext.get().getAuthenticationData();

			UsuarioVO usuVO = dbSession.findByPK(UsuarioVO.class, auth.getUserID());

			usuVO.setFOTO(null);
			usuVO.save();
		} finally {
			DBSessionManager.close(dbSession);
		}
	}

	@Transactional
	@RestCall
	@Override
	public void savePicture() {
		IDBSession dbSession = null;
		try {
			dbSession = DBSessionManager.open();
			AuthenticationData auth = RestCallContext.get().getAuthenticationData();

			UsuarioVO usuVO = dbSession.findByPK(UsuarioVO.class, auth.getUserID());
			byte[] imageContent = UserPictureUtils.readFromTempFolder(RestCallContext.get().getRequest());

			usuVO.setFOTO(imageContent);
			usuVO.save();
		} finally {
			DBSessionManager.close(dbSession);
		}
	}

	@Transactional
	@RestCall(inputTypeClass = IUserServices.LoginInput.class, requiresLogin = false)
	@AuthenticationService
	@Override
	public AuthenticationData login() {
		IDBSession dbSession = null;
		try {
			LoginInput li = (LoginInput) RestCallContext.get().getInputObject();

			dbSession = DBSessionManager.open();

			Query<UsuarioVO> q = dbSession.buildQuery(UsuarioVO.class);

			final Collection<UsuarioVO> result = q.execute("email = :p1 and psw = :p2", li.getEmail(), li.getPassword());

			if (result.isEmpty()) {
				throw new IllegalStateException(i18n.get("error_invalid_login"));
			}

			UsuarioVO vo = result.iterator().next();

			vo.set("DHULTLOGIN", new Timestamp(System.currentTimeMillis()));

			vo.save();

			AuthenticationData ad = new AuthenticationData(vo.getIDUSUARIO(), RestCallContext.get().getTenantID(), vo.getNOME(), vo.getEMAIL());

			ad.setLocale(RestCallContext.get().getCurrentUserLocale());
			
			return ad;
		} finally {
			DBSessionManager.close(dbSession);
		}
	}

	@Transactional
	@RestCall(inputTypeClass = IUserServices.LoginInput.class, requiresLogin = false)
	@Override
	public void sendPasswordRecoveryMessage() {
		IDBSession dbSession = null;
		try {
			LoginInput li = (LoginInput) RestCallContext.get().getInputObject();

			dbSession = DBSessionManager.open();

			Collection<UsuarioVO> result = dbSession.buildQuery(UsuarioVO.class).execute("this.email = :p1", li.getEmail());

			if (result.isEmpty()) {
				throw new IllegalStateException(i18n.get("error_user_data_not_found"));
			}

			UsuarioVO usuVO = result.iterator().next();

			FilaEmailVO msgVO = dbSession.emptyVO(FilaEmailVO.class);

			msgVO.set("DHINCLUSAO", new Timestamp(System.currentTimeMillis()));
			msgVO.set("EMAILDEST", usuVO.getEMAIL());
			msgVO.set("ASSUNTO", i18n.get("txt_pass_reset_mail_subject"));

			buildPassRecoveryBody(msgVO, usuVO);

			msgVO.set("IDCONTASMTP", 1); // TODO pegar a conta global

			usuVO.save();
			msgVO.save();
		} finally {
			DBSessionManager.close(dbSession);
		}
	}

	@Transactional
	@RestCall(inputTypeClass = IUserServices.PasswordResetInput.class, requiresLogin = false)
	@Override
	public void resetPassword() {
		IDBSession dbSession = null;
		try {
			PasswordResetInput li = (PasswordResetInput) RestCallContext.get().getInputObject();

			dbSession = DBSessionManager.open();

			Collection<UsuarioVO> result = dbSession.buildQuery(UsuarioVO.class).execute("this.PSWRESETID = :p1", li.getResetID());

			if (result.isEmpty()) {
				throw new IllegalStateException(i18n.get("error_pass_reset_invalid_link"));
			}

			UsuarioVO usuVO = result.iterator().next();

			usuVO.setPSW(li.getPassword());
			usuVO.set("PSWRESETID", (String) null);

			usuVO.save();
		} finally {
			DBSessionManager.close(dbSession);
		}
	}

	private void buildPassRecoveryBody(FilaEmailVO msgVO, UsuarioVO usuVO) {

		String resetID = UUID.randomUUID().toString(); // ID para esse reset
		String externalURL = "http://localhost:8080"; // TODO buscar de um parametro
		String appPath = RestCallContext.get().getRequest().getContextPath();
		String link = externalURL + appPath + "/" + RestCallContext.get().getTenantID() + "/pswreset/" + resetID;

		String body = i18n.get("txt_pass_reset_mail_body",usuVO.asString("NOME"),link);

		msgVO.set("MIMETYPE", "text/html");
		msgVO.set("CORPO", body);
		
		usuVO.set("PSWRESETID", resetID);
	}
}
